package cn.tedu.v3_1;

import com.sun.prism.shader.AlphaTexture_Color_AlphaTest_Loader;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import org.omg.CORBA.PUBLIC_MEMBER;

import java.io.*;
import java.net.*;
import java.util.*;

/**
 * 多人聊天室  Version3.1
 * [优化版本],功能：客户端与服务器端可以双向沟通
 * 优化①：导入包开始优化
 *    ②：动态数据全部封装封装到类上，代码更加易用
 *    ③读入和写出   操作定义----构造器 | 功能
 *      构造器主要用于对象初始化，Client对象初始化：添加IP和端口号
 *                                           流创建添加
 *      优点：1.减少代码重复和复杂度
 *           2.代码结构清晰
 *           3.客户端创建之初，明确具备读写功能
 *      构造器：读写定义
 *      start方法：保留读写功能
 *
 * 问题1:标准IP流置空,线程中使用BufferedRead  无法到达【作用域不够】
 *   流置空的问题更适合在短期、简单场景中使用，不一定保证对象正常释放
 *   有可能爆出null,实际软件开发中使用JavaOOP封装思路替换置空方式
 *   置空流  方式         升级     JavaOOP 封装方式：流私有化属性：流、ip、socket
 *
 *
 *   好处：①数据保护：本类下可访问，确保其他类无法直接访问
 *        ②易用性和安全星：指控操作--目的：赋值、关闭、紧邻try上
 *                       私有化属性--->便于修改，流正确关闭
 */
public class Client {
    //优化②：动态数据全部私有化属性到类上---方便修改
    //使用Map的K,V存储用户信息（用户名，socket），模拟登陆现象
    private static Map<String, String> userDatabase=new HashMap<String, String>();//线程安全
    private static final String HOST="127.0.0.1";
    private static final Integer PORT=3333;
    private Socket socket;
    //1.置空流  升级 JavaOOP  封装--私有化属性：本类任意地方都可以使用
    private BufferedReader br;
    private PrintWriter pw;
    private String ip;
    public Client(){
        try {
            socket = new Socket(HOST, PORT);
            ip=socket.getInetAddress().getHostAddress();
            br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF8"));
            pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF8")), true);
        } catch (SocketException e) {
            System.out.println("连接被重置或者断开");
        } catch (UnknownHostException e) {
            System.out.println("IP地址有问题，请询问服务器端");
        }catch (IOException e) {
            System.out.println("客户端主动退出了");
        }
    }

    public void start() {

        try {

            new Thread(() -> {
                try {
                    //1.4 线程中--创建变量--接受服务器端发来的文本
                    String message;
                    //1.5 一直接受客户但发来的消息:message只要有数据一直输出
                    while ((message = br.readLine()) != null) {
                        System.out.println(ip + "服务器端说：" + message/*br.readLine()*/);
                    }
                } catch (IOException e) {
                    System.out.println("服务器端断开了");
                }
            }).start();

            System.out.println(ip + "客户端：请输入文字：");
            Scanner input = new Scanner(System.in);
            while (true) {
                String say = input.nextLine();
                pw.println("客户端说" + say);
                System.out.println("发送");
                System.out.println("客户端请输入： ");
            }
        }  finally {
            if (br != null)
                try {
                    br.close();
                } catch (IOException e) {
                    System.out.println("客户端离开");
                }
                    if (pw != null)
                        pw.close();
                    try {
                        socket.close();
                    } catch (IOException e) {
                        System.out.println("客户端离开");
                    }
                    if (socket != null && !socket.isClosed()) {
                        System.out.println(ip + "客户端关闭成功");
                        try {
                            socket.close();
                        } catch (IOException e) {
                            System.out.println(ip + "客户端关闭失败");
                        }
                    }
                }
        }
    // 验证用户名和密码的方法
    private static boolean authenticate(String username, String password) {
        String storedPassword = userDatabase.get(username);
        return storedPassword != null && storedPassword.equals(password);
    }
    public static void main(String[] args) {
        new Client().start();

    }
}